#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include "nveth.h"

const char* nveth_name = "nveth";
struct net_device *gnveth;
extern int register_bpf_nveth_kfunc(void);

static int nveth_xmit(struct sk_buff *skb, struct net_device *dev)
{
	dev->stats.tx_dropped++;
	dev_kfree_skb(skb);
	return 0;
}

static const struct net_device_ops nveth_netdev_ops = {
        .ndo_start_xmit = nveth_xmit,
        .ndo_change_mtu = NULL,
        .ndo_do_ioctl = NULL,
        .ndo_setup_tc	= nveth_testflow_setup_tc,
};


static void nveth_setup(struct net_device *dev)
{
	ether_setup(dev);

	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
}


int nveth_create_interface(void)
{
	int err = 0 ;
	struct net_device *dev;

	dev = alloc_netdev(sizeof(struct nveth_priv), nveth_name, NET_NAME_USER, nveth_setup);

	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
	dev->priv_flags |= IFF_NO_QUEUE;
	dev->priv_flags |= IFF_PHONY_HEADROOM;

	dev->netdev_ops = &nveth_netdev_ops;
	dev->max_mtu = ETH_MAX_MTU;

	err = register_netdev(dev);
	if (err < 0)
	{
		free_netdev(dev);
		return err;
	}

	eth_hw_addr_random(dev);

	gnveth = dev;

	netif_carrier_on(dev);

	return 0;
}

int nveth_delete_interface(void)
{
	netif_carrier_off(gnveth);
	unregister_netdev(gnveth);

	return 0;
}

static __init int nveth_init(void)
{
  register_bpf_nveth_kfunc();
	return nveth_create_interface();
}

static __exit void nveth_exit(void)
{
	nveth_delete_interface();
}

module_init(nveth_init);
module_exit(nveth_exit);

MODULE_DESCRIPTION("Virtual Ethernet");
MODULE_LICENSE("GPL v2");

